Spring Boot ORM এ Query Methods এবং Custom Queries ব্যবহার করে ডেটাবেস থেকে ডেটা রিট্রিভ বা ম্যানিপুলেশন করা খুবই সহজ। Spring Data JPA ডেভেলপারদের জন্য প্রি-ডিফাইন্ড মেথড এবং কাস্টম কুয়েরি লেখার জন্য ফ্লেক্সিবিলিটি প্রদান করে।
Query Methods
Query Methods Spring Data JPA এর একটি ফিচার, যা মেথডের নাম অনুসারে ডেটাবেস কুয়েরি তৈরি করে। এর মাধ্যমে SQL বা JPQL কুয়েরি না লিখেই ডেটা ফিল্টার করা যায়।
উদাহরণ: Query Methods
ধরা যাক, আমাদের একটি Product Entity রয়েছে এবং আমরা তার জন্য কিছু ফিল্টারিং মেথড তৈরি করতে চাই।
১. ProductRepository ইন্টারফেস
import org.springframework.data.jpa.repository.JpaRepository;
import java.util.List;
public interface ProductRepository extends JpaRepository<Product, Long> {
List<Product> findByName(String name);
List<Product> findByPriceLessThan(Double price);
List<Product> findByNameContaining(String keyword);
List<Product> findByPriceBetween(Double minPrice, Double maxPrice);
}
২. ব্যবহারের উদাহরণ
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RequestParam;
import org.springframework.web.bind.annotation.RestController;
import java.util.List;
@RestController
public class ProductController {
@Autowired
private ProductRepository productRepository;
@GetMapping("/products/by-name")
public List<Product> getProductsByName(@RequestParam String name) {
return productRepository.findByName(name);
}
@GetMapping("/products/by-price")
public List<Product> getProductsByPrice(@RequestParam Double price) {
return productRepository.findByPriceLessThan(price);
}
}
উপকারিতা:
- কোড সহজ ও সংক্ষিপ্ত।
- SQL বা JPQL লেখার প্রয়োজন নেই।
- ডেটাবেস ফিল্টারিং সহজে কনফিগার করা যায়।
Custom Queries
Spring Data JPA ডিফল্ট Query Methods ছাড়াও কাস্টম কুয়েরি লেখার সুযোগ দেয়। এটি জটিল কুয়েরির জন্য খুবই কার্যকর।
কাস্টম কুয়েরি লেখার জন্য @Query ব্যবহার
Spring Data JPA এর @Query এনোটেশন ব্যবহার করে কাস্টম কুয়েরি লেখা যায়।
উদাহরণ: JPQL ব্যবহার
import org.springframework.data.jpa.repository.JpaRepository;
import org.springframework.data.jpa.repository.Query;
import org.springframework.data.repository.query.Param;
import java.util.List;
public interface ProductRepository extends JpaRepository<Product, Long> {
@Query("SELECT p FROM Product p WHERE p.name = :name")
List<Product> findProductsByName(@Param("name") String name);
@Query("SELECT p FROM Product p WHERE p.price > :price")
List<Product> findProductsWithPriceGreaterThan(@Param("price") Double price);
}
উদাহরণ: Native Query ব্যবহার
import org.springframework.data.jpa.repository.Query;
import org.springframework.data.repository.query.Param;
import java.util.List;
public interface ProductRepository extends JpaRepository<Product, Long> {
@Query(value = "SELECT * FROM Product WHERE name = :name", nativeQuery = true)
List<Product> findProductsByNameNative(@Param("name") String name);
@Query(value = "SELECT * FROM Product WHERE price < :price", nativeQuery = true)
List<Product> findProductsByPriceNative(@Param("price") Double price);
}
Query Methods এবং Custom Queries এর পার্থক্য
| বৈশিষ্ট্য | Query Methods | Custom Queries |
|---|---|---|
| কোডের সরলতা | শুধুমাত্র মেথডের নাম অনুসারে কাজ করে। | কাস্টম কুয়েরি লিখতে হয়। |
| ফ্লেক্সিবিলিটি | সীমিত (মেথড নামের কাঠামো অনুসরণ করতে হয়)। | বেশি (কাস্টম SQL বা JPQL লেখা যায়)। |
| পারফরম্যান্স | দ্রুত (ডিফল্ট কুয়েরি অটোমেটেড)। | জটিল এবং কাস্টম লজিক প্রয়োগযোগ্য। |
| ব্যবহার ক্ষেত্র | সাধারণ ফিল্টারিং বা ডেটা রিট্রিভের জন্য। | জটিল ফিল্টারিং বা স্পেসিফিক কুয়েরির জন্য। |
উদাহরণ প্রজেক্ট
১. কাস্টম কুয়েরি কন্ট্রোলার
@RestController
@RequestMapping("/products")
public class ProductController {
@Autowired
private ProductRepository productRepository;
@GetMapping("/custom-query")
public List<Product> getProductsByCustomQuery(@RequestParam String name) {
return productRepository.findProductsByName(name);
}
@GetMapping("/native-query")
public List<Product> getProductsByNativeQuery(@RequestParam Double price) {
return productRepository.findProductsByPriceNative(price);
}
}
২. টেস্টিং
HTTP GET রিকোয়েস্ট:
/products/custom-query?name=Laptop/products/native-query?price=500.0
সারাংশ
Spring Boot ORM এ Query Methods সহজ ডেটা ফিল্টারিংয়ের জন্য ব্যবহার করা হয়, যেখানে Custom Queries জটিল বা বিশেষ ডেটাবেস অপারেশনের জন্য ব্যবহৃত হয়। উভয় পদ্ধতি ডেভেলপমেন্টে ফ্লেক্সিবিলিটি এবং ডেটা এক্সেস সহজ করে তোলে।
স্প্রিং ডেটা JPA-তে Query Methods হলো এমন একটি পদ্ধতি যেখানে মেথডের নাম অনুসারে ডেটাবেজ কোয়েরি স্বয়ংক্রিয়ভাবে তৈরি হয়। এটি ডেভেলপারদের ম্যানুয়াল SQL কোয়েরি লেখার প্রয়োজনীয়তা দূর করে এবং সহজভাবে ডেটা অনুসন্ধান, হালনাগাদ বা মুছে ফেলার সুযোগ দেয়।
Query Methods কীভাবে কাজ করে?
স্প্রিং ডেটা JPA-এর একটি শক্তিশালী বৈশিষ্ট্য হলো এটি মেথডের নাম বিশ্লেষণ করে ডেটাবেজ কোয়েরি তৈরি করতে পারে। মেথডের নামের কাঠামো অনুযায়ী স্প্রিং ডেটা JPA নির্ধারণ করে কী ধরণের কোয়েরি তৈরি করতে হবে।
মূল কাঠামো:
findBy[Property][Condition]
findBy: এটি ডেটা খোঁজার নির্দেশ দেয়।[Property]: Entity ক্লাসের একটি ফিল্ড।[Condition]: নির্দিষ্ট শর্ত যেমন Equals, Like, GreaterThan ইত্যাদি।
Query Methods এর উদাহরণ
১. সরল উদাহরণ
import org.springframework.data.jpa.repository.JpaRepository;
import java.util.List;
public interface ProductRepository extends JpaRepository<Product, Long> {
List<Product> findByName(String name); // প্রোডাক্ট নাম অনুযায়ী খুঁজবে
}
উপরের উদাহরণে, findByName মেথডের মাধ্যমে name ফিল্ডের ভিত্তিতে ডেটা রিটার্ন করা হবে। স্প্রিং ডেটা JPA এই মেথডের জন্য SQL কোয়েরি স্বয়ংক্রিয়ভাবে তৈরি করবে:
SELECT * FROM product WHERE name = ?;
২. শর্তযুক্ত উদাহরণ
List<Product> findByPriceGreaterThan(Double price); // নির্ধারিত মূল্যের চেয়ে বেশি প্রোডাক্ট খুঁজবে
উপরের মেথড অনুযায়ী SQL কোয়েরি হবে:
SELECT * FROM product WHERE price > ?;
৩. একাধিক শর্ত
List<Product> findByNameAndPrice(String name, Double price); // নাম ও মূল্য একসাথে শর্ত দিয়ে খুঁজবে
SQL কোয়েরি:
SELECT * FROM product WHERE name = ? AND price = ?;
৪. লাইক (Like) অপারেটর ব্যবহার
List<Product> findByNameContaining(String keyword); // নির্দিষ্ট শব্দের উপস্থিতি খুঁজবে
SQL কোয়েরি:
SELECT * FROM product WHERE name LIKE %?%;
৫. সাজানোর (Sorting) জন্য মেথড
List<Product> findByNameOrderByPriceAsc(String name); // নাম অনুযায়ী সাজানো তালিকা প্রদান করবে
SQL কোয়েরি:
SELECT * FROM product WHERE name = ? ORDER BY price ASC;
Query Methods এর মাধ্যমে কাস্টম কোয়েরি
স্প্রিং ডেটা JPA-তে কাস্টম কোয়েরি তৈরি করার জন্য @Query অ্যানোটেশন ব্যবহার করা হয়।
উদাহরণ:
import org.springframework.data.jpa.repository.Query;
import org.springframework.data.repository.query.Param;
public interface ProductRepository extends JpaRepository<Product, Long> {
@Query("SELECT p FROM Product p WHERE p.name = :name AND p.price > :price")
List<Product> findProductsByNameAndPrice(
@Param("name") String name,
@Param("price") Double price
);
}
Query Methods এর সুবিধা
- কোড স্বচ্ছতা: কোয়েরি মেথডের নামই বুঝিয়ে দেয় এটি কী কাজ করবে।
- স্বয়ংক্রিয় কোয়েরি জেনারেশন: ডেভেলপারদের SQL কোয়েরি লেখার প্রয়োজন নেই।
- সহজ রক্ষণাবেক্ষণ: কোড পরিবর্তন করলে SQL পরিবর্তনের দরকার পড়ে না।
- কাস্টম কোয়েরি সমর্থন: বিশেষ শর্তযুক্ত কোয়েরি তৈরির জন্য @Query ব্যবহারের সুযোগ।
Query Methods এর চেকলিস্ট
- মেথডের নাম সঠিকভাবে এবং স্পষ্টভাবে তৈরি করতে হবে।
- Entity ফিল্ডের নাম অনুসারে মেথডের নাম ব্যবহার করতে হবে।
- প্রয়োজন হলে কাস্টম কোয়েরি @Query ব্যবহার করতে হবে।
সারসংক্ষেপ
স্প্রিং ডেটা JPA-এর Query Methods ডেটাবেস অপারেশনকে আরও সহজ এবং কার্যকর করে তোলে। মেথডের নাম অনুযায়ী স্বয়ংক্রিয় SQL কোয়েরি তৈরি হওয়ায় ডেভেলপারদের কাজের সময় সাশ্রয় হয় এবং ডেটাবেস ইন্টিগ্রেশন আরও মসৃণ হয়। Query Methods এবং কাস্টম কোয়েরি উভয়ই ডেটা ম্যানিপুলেশনে উন্নত সুবিধা প্রদান করে।
Spring Data JPA-তে Method Naming Convention ব্যবহার করে ডেটাবেস থেকে ডেটা রিট্রিভ করার জন্য কাস্টম কোয়েরি তৈরি করা যায়। এখানে ম্যানুয়াল SQL কোয়েরি লেখার প্রয়োজন হয় না; মেথডের নাম অনুযায়ী Spring Data JPA স্বয়ংক্রিয়ভাবে কোয়েরি তৈরি করে এবং এক্সিকিউট করে।
Naming Convention কিভাবে কাজ করে?
Method Naming Convention অনুসরণ করে মেথডের নামের ভিত্তিতে Spring Data JPA ডেটাবেস অপারেশনের জন্য SQL কোয়েরি জেনারেট করে। মেথডের নাম মূলত findBy, readBy, বা getBy দিয়ে শুরু হয় এবং এরপরে ফিল্ডের নাম এবং লজিকাল অপারেশন যুক্ত করা হয়।
সাধারণ গঠন
findBy<FieldName><Operation>
উদাহরণ
টেবিল: User
| ID | Name | Age | |
|---|---|---|---|
| 1 | John Doe | john@example.com | 25 |
| 2 | Jane Smith | jane@example.com | 30 |
Entity ক্লাস
@Entity
public class User {
@Id
@GeneratedValue(strategy = GenerationType.IDENTITY)
private Long id;
private String name;
private String email;
private Integer age;
// Getters and Setters
}
Repository ইন্টারফেস
import org.springframework.data.jpa.repository.JpaRepository;
import java.util.List;
public interface UserRepository extends JpaRepository<User, Long> {
List<User> findByName(String name); // নাম অনুসারে খুঁজুন
List<User> findByAgeGreaterThan(Integer age); // নির্দিষ্ট বয়সের বেশি
List<User> findByNameAndAge(String name, Integer age); // নাম এবং বয়স অনুযায়ী
}
Naming Convention এর কিছু KeyWords
| Keyword | অর্থ |
|---|---|
| And | দুটি শর্ত যুক্ত করার জন্য। |
| Or | দুটি শর্তের যেকোনো একটি সত্য হলে। |
| Is, Equals | নির্দিষ্ট মানের সমান হলে। |
| Between | দুটি মানের মধ্যে হলে। |
| LessThan | নির্দিষ্ট মানের চেয়ে কম হলে। |
| GreaterThan | নির্দিষ্ট মানের চেয়ে বেশি হলে। |
| Like | প্যাটার্ন মিললে। |
| StartingWith | নির্দিষ্ট স্ট্রিং দিয়ে শুরু হলে। |
| EndingWith | নির্দিষ্ট স্ট্রিং দিয়ে শেষ হলে। |
| Containing | নির্দিষ্ট স্ট্রিং ধারণ করলে। |
উদাহরণসমূহ
১. নির্দিষ্ট নাম অনুসারে ডেটা খুঁজুন
List<User> users = userRepository.findByName("John Doe");
SQL কোয়েরি:
SELECT * FROM user WHERE name = 'John Doe';
২. নির্দিষ্ট বয়সের চেয়ে বেশি ডেটা খুঁজুন
List<User> users = userRepository.findByAgeGreaterThan(25);
SQL কোয়েরি:
SELECT * FROM user WHERE age > 25;
৩. নাম এবং বয়স উভয়ের শর্ত মিললে ডেটা খুঁজুন
List<User> users = userRepository.findByNameAndAge("Jane Smith", 30);
SQL কোয়েরি:
SELECT * FROM user WHERE name = 'Jane Smith' AND age = 30;
৪. নির্দিষ্ট প্যাটার্ন অনুযায়ী ডেটা খুঁজুন
List<User> users = userRepository.findByEmailEndingWith("@example.com");
SQL কোয়েরি:
SELECT * FROM user WHERE email LIKE '%@example.com';
সুবিধা
- কোড রিডিবিলিটি বৃদ্ধি: Method নাম পড়েই বোঝা যায় এটি কী কাজ করবে।
- অটোমেশন: Spring Data JPA স্বয়ংক্রিয়ভাবে SQL কোয়েরি তৈরি করে।
- কম কোড: ম্যানুয়াল SQL কোয়েরি লেখার প্রয়োজন নেই।
- ডায়নামিক অপারেশন: লজিক অনুযায়ী বিভিন্ন শর্ত তৈরি করা সহজ।
Spring Data JPA-এর Method Naming Convention ডেটাবেস অপারেশন সহজ এবং কার্যকর করে, বিশেষত যেখানে কমপ্লেক্স SQL কোয়েরি লেখার প্রয়োজন নেই। এটি ডেভেলপমেন্ট সময় এবং প্রচেষ্টা বাঁচায়।
@Query অ্যানোটেশন কী?
Spring Data JPA-তে @Query অ্যানোটেশন ব্যবহার করে কাস্টম SQL বা JPQL (Java Persistence Query Language) কোয়েরি লেখা যায়। এটি এমন পরিস্থিতিতে ব্যবহৃত হয় যেখানে ডিফল্ট মেথডের মাধ্যমে কাঙ্ক্ষিত ফলাফল পাওয়া সম্ভব নয়। @Query অ্যানোটেশনের মাধ্যমে ডেভেলপাররা সরাসরি জটিল এবং নির্দিষ্ট ডেটা অপারেশনের জন্য কোয়েরি কাস্টমাইজ করতে পারেন।
@Query এর বৈশিষ্ট্য
- JPQL এবং Native Query: @Query অ্যানোটেশনে JPQL (Object-Oriented Query) এবং Native SQL (Raw Query) লেখা সম্ভব।
- প্যারামিটারাইজড কুয়েরি: প্লেসহোল্ডার বা নামযুক্ত প্যারামিটারের মাধ্যমে কোয়েরি আরও নিরাপদ করা যায়।
- কাস্টম ফলাফল: জটিল ডেটা অপারেশনের জন্য কাস্টম কুয়েরি লিখতে ব্যবহার করা হয়।
@Query ব্যবহার করে কাস্টম কুয়েরি লেখার ধাপ
১. সাধারণ কুয়েরি
একটি নির্দিষ্ট নামের প্রোডাক্ট খুঁজে বের করতে @Query ব্যবহার করা যায়:
import org.springframework.data.jpa.repository.Query;
import org.springframework.data.repository.query.Param;
import org.springframework.data.jpa.repository.JpaRepository;
public interface ProductRepository extends JpaRepository<Product, Long> {
@Query("SELECT p FROM Product p WHERE p.name = :name")
List<Product> findByName(@Param("name") String name);
}
ব্যবহার:
List<Product> products = productRepository.findByName("Laptop");
products.forEach(System.out::println);
২. Native Query
Native SQL কুয়েরি ব্যবহার করতে nativeQuery প্যারামিটার true করতে হবে:
@Query(value = "SELECT * FROM products WHERE price > :price", nativeQuery = true)
List<Product> findProductsAbovePrice(@Param("price") Double price);
ব্যবহার:
List<Product> products = productRepository.findProductsAbovePrice(50000.0);
products.forEach(System.out::println);
@Query এর মাধ্যমে জটিল কুয়েরি
১. প্রাইসের সীমার মধ্যে প্রোডাক্ট খুঁজে আনা
@Query("SELECT p FROM Product p WHERE p.price BETWEEN :minPrice AND :maxPrice")
List<Product> findProductsInPriceRange(@Param("minPrice") Double minPrice, @Param("maxPrice") Double maxPrice);
ব্যবহার:
List<Product> products = productRepository.findProductsInPriceRange(30000.0, 70000.0);
products.forEach(System.out::println);
২. নাম ও প্রাইসের ভিত্তিতে ফিল্টার
@Query("SELECT p FROM Product p WHERE p.name LIKE %:name% AND p.price < :price")
List<Product> findByNameAndPriceLessThan(@Param("name") String name, @Param("price") Double price);
ব্যবহার:
List<Product> products = productRepository.findByNameAndPriceLessThan("Lap", 80000.0);
products.forEach(System.out::println);
Pagination এবং Sorting সহ @Query
Spring Data JPA-এর পেজিনেশন ও সোর্টিং ফিচার @Query এর সাথে ব্যবহার করা যায়:
@Query("SELECT p FROM Product p WHERE p.price > :price")
Page<Product> findProductsWithPagination(@Param("price") Double price, Pageable pageable);
ব্যবহার:
Pageable pageable = PageRequest.of(0, 5, Sort.by("price").ascending());
Page<Product> productPage = productRepository.findProductsWithPagination(40000.0, pageable);
productPage.getContent().forEach(System.out::println);
@Query এর সুবিধা
- জটিল কুয়েরি সহজে লেখা যায়।
- কোড আরও কাস্টমাইজড এবং অ্যাপ্লিকেশন লজিক অনুযায়ী ফ্লেক্সিবল হয়।
- Native SQL এবং JPQL উভয়কেই সাপোর্ট করে।
@Query এর সীমাবদ্ধতা
- বড় এবং জটিল কুয়েরির ক্ষেত্রে মেইনটেনেন্স কঠিন হতে পারে।
- ডাইনামিক কুয়েরির জন্য Criteria API বা Specification ব্যবহার করতে হতে পারে।
- Native Query এর ক্ষেত্রে ডাটাবেসের উপর নির্ভরশীলতা বৃদ্ধি পায়।
স্প্রিং ডেটা জেপিএ (Spring Data JPA) ডেটাবেস অপারেশন পরিচালনার জন্য স্বয়ংক্রিয়ভাবে তৈরি মেথড সরবরাহ করে। তবে অনেক সময় কাস্টম কুয়েরি (Custom Query) প্রয়োজন হয়, যেখানে স্পেসিফিক ডেটা ফিল্টারিং বা জটিল লজিক প্রয়োগ করা হয়। স্প্রিং ডেটা জেপিএ কাস্টম কুয়েরি তৈরি করতে JPQL (Java Persistence Query Language) বা Native SQL Query সমর্থন করে।
কাস্টম কুয়েরি কি?
কাস্টম কুয়েরি হলো এমন কুয়েরি যা স্পেসিফিক চাহিদা পূরণের জন্য ম্যানুয়ালি লেখা হয়। এটি ডেটাবেস থেকে নির্দিষ্ট ডেটা ফিল্টার বা জটিল ডেটা রিট্রাইভ করতে ব্যবহৃত হয়।
কাস্টম কুয়েরি তৈরি করার ধাপ
Entity ক্লাস তৈরি
Entity ক্লাস ব্যবহার করে ডেটাবেস টেবিলের ম্যাপিং করতে হবে।
Repository ইন্টারফেস তৈরি
Repository ইন্টারফেসে কাস্টম কুয়েরি ডিফাইন করতে হবে।
@Query এনোটেশন ব্যবহার
কাস্টম কুয়েরি লিখতে @Query এনোটেশন ব্যবহার করতে হয়। এটি JPQL বা Native Query সমর্থন করে।
উদাহরণ
Entity ক্লাস
import jakarta.persistence.Entity;
import jakarta.persistence.Id;
@Entity
public class User {
@Id
private Long id;
private String name;
private String email;
// Getter এবং Setter
public Long getId() {
return id;
}
public void setId(Long id) {
this.id = id;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public String getEmail() {
return email;
}
public void setEmail(String email) {
this.email = email;
}
}
Repository ইন্টারফেস
import org.springframework.data.jpa.repository.JpaRepository;
import org.springframework.data.jpa.repository.Query;
import org.springframework.data.repository.query.Param;
import java.util.List;
public interface UserRepository extends JpaRepository<User, Long> {
// কাস্টম JPQL কুয়েরি
@Query("SELECT u FROM User u WHERE u.name = :name")
List<User> findUsersByName(@Param("name") String name);
// কাস্টম Native SQL কুয়েরি
@Query(value = "SELECT * FROM user WHERE email = :email", nativeQuery = true)
User findUserByEmail(@Param("email") String email);
}
Controller
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.web.bind.annotation.*;
import java.util.List;
@RestController
@RequestMapping("/users")
public class UserController {
@Autowired
private UserRepository userRepository;
@GetMapping("/by-name/{name}")
public List<User> getUsersByName(@PathVariable String name) {
return userRepository.findUsersByName(name);
}
@GetMapping("/by-email/{email}")
public User getUserByEmail(@PathVariable String email) {
return userRepository.findUserByEmail(email);
}
}
@Query এনোটেশনের সুবিধা
- জটিল কুয়েরি সমর্থন: জটিল ফিল্টারিং এবং কন্ডিশনাল লজিক যুক্ত কুয়েরি তৈরি করা যায়।
- JPQL এবং Native Query: দুই ধরনের কুয়েরি সমর্থন করে।
- ডাইনামিক ইনপুট প্যারামিটার: @Param এর মাধ্যমে ইনপুট ডাইনামিকভাবে সেট করা যায়।
JPQL এবং Native Query এর তুলনা
| বৈশিষ্ট্য | JPQL | Native Query |
|---|---|---|
| লেখার ধরন | JPA স্পেসিফিক, জাভা অবজেক্ট ভিত্তিক | ডাটাবেস স্পেসিফিক, সরাসরি SQL কোয়েরি |
| ডেটাবেস নির্ভরতা | ডেটাবেস ইন্ডিপেনডেন্ট | ডেটাবেস নির্ভর |
| ব্যবহারিক ক্ষেত্র | সহজ এবং সাধারণ কুয়েরির জন্য উপযোগী | জটিল এবং ডাটাবেস-স্পেসিফিক কুয়েরির জন্য |
সারমর্ম
স্প্রিং বুট ORM-এ কাস্টম কুয়েরি ব্যবহার করে জটিল ডেটাবেস অপারেশন সহজে পরিচালনা করা যায়। @Query এনোটেশন এবং এর সাথে JPQL বা Native Query এর সমন্বয় করে ডেটাবেস থেকে নির্দিষ্ট ডেটা রিট্রাইভ করা কার্যকর। বড় বা জটিল অ্যাপ্লিকেশনের জন্য এটি একটি শক্তিশালী ফিচার।
Read more